package com.yao.seckill.web.aop.aspect;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Copyright (C), 2022-2022, 姚兵
 * Author: 32210
 * Date: 2022/8/31 19:30
 * FileName: LogAspect
 * Description: 日志切面
 */


@Aspect @Component
@Slf4j
public class LogAspect {

    @Pointcut("execution(* com.yao.seckill.web.controller.*.*(..))")
    public void logPointcut(){}

    @Around("logPointcut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint){
        try {
            long startTime=System.currentTimeMillis();
            //请求之前打印
            preLogPrint(proceedingJoinPoint);
            //执行方法
            Object result = proceedingJoinPoint.proceed();
            //打印返回结果
            long endTime=System.currentTimeMillis();

            postLogPrint(proceedingJoinPoint,result,endTime-startTime);

            return result;
        }catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    public  void preLogPrint(ProceedingJoinPoint proceedingJoinPoint){
        //getSignature());是获取到这样的信息 :修饰符+ 包名+组件名(类名) +方法名
        MethodSignature methodSignature= (MethodSignature) proceedingJoinPoint.getSignature();
        //getAnnotation:方法如果存在这样的注释，则返回指定类型的元素的注释，否则为null
        log.info("==============================开始记录日志===============================");
        //proceedingJoinPoint.getTarget():获取切入点所在目标对象
        String className=proceedingJoinPoint.getTarget().getClass().getName();
        String methodName=methodSignature.getName();
        //这里返回的是切入点方法的参数列表
        Object[] args=proceedingJoinPoint.getArgs();
        String[] parameterNames = methodSignature.getParameterNames();
        Map<String,Object> paramMap=new LinkedHashMap<>();
        int index=0;
        for (String paramName:parameterNames){
            paramMap.put(paramName,args[index++]);
        }
        log.info("{}.{}",className,methodName);
        log.info("请求的参数是:{}",paramMap.isEmpty()?"{}":JSONObject.toJSONString(paramMap));
    }


    public void postLogPrint(ProceedingJoinPoint proceedingJoinPoint,Object result,long time){
        //getSignature());是获取到这样的信息 :修饰符+ 包名+组件名(类名) +方法名
        //getSignature());是获取到这样的信息 :修饰符+ 包名+组件名(类名) +方法名
        MethodSignature methodSignature= (MethodSignature) proceedingJoinPoint.getSignature();
        //proceedingJoinPoint.getTarget():获取切入点所在目标对象
        String className=proceedingJoinPoint.getTarget().getClass().getName();
        String methodName=methodSignature.getName();
        log.info("请求的结果是:{}",JSONObject.toJSONString(result));
        log.info("执行时长:{}s",time*1.0/1000);
        log.info("{}.{}",className,methodName);
        log.info("==============================开始结束日志===============================");
    }
}
